﻿using System;
using System.Collections.Generic;
using LogSystem;
using UnityEditor;
using UnityEngine;
using Yoozoo.Gameplay.Liberty.Pool;

namespace Yoozoo.Gameplay.Liberty.AI
{
    [Serializable]
    public class GraphPathHolder
    {
        public int graphId;
        public string resPath;
        public GameObject graph;
    }
    
    public class LibertyAIManager : MonoBehaviour
    {

        [SerializeField]
        private List<GraphPathHolder> graphs;

        private Dictionary<string, GameObject> graphMap;
        private Dictionary<int, string> id2GraphPathMap;

        private Dictionary<string, LibertyBTreePool> _libertyBTreePoolMap = 
            new Dictionary<string, LibertyBTreePool>();

        private Dictionary<int, string> _uniqueId2GraphResPathMap = new Dictionary<int, string>(); 

        [Space(20)]
        // [SerializeField]
        // private AstarPath _pathfinder;
        [SerializeField]
        private LibertyNpcBirthManager _npcBirthManager;
        public LibertyNpcBirthManager NpcBirthManager => _npcBirthManager;

        [SerializeField] 
        private DynamicNpcManager _dynamicNpcManager;
        public DynamicNpcManager DynamicNpcManager => _dynamicNpcManager;
        
        [SerializeField] 
        private LibertyCarBirthManager _carBirthManager;
        public LibertyCarBirthManager CarBirthManager => _carBirthManager;

        [Space(20)] 
        public AIBirthData debugBirthData;
        public Transform debugTransform;
        public int debugGraphId;
        
        
        private void Awake()
        {
            graphMap = new Dictionary<string, GameObject>(graphs.Count);
            id2GraphPathMap = new Dictionary<int, string>(graphs.Count);
            
            foreach (var graph in graphs)
            {
                graphMap[graph.resPath] = graph.graph;

                LibertyBTreePool bTreePool = new LibertyBTreePool(graph, 10, 20);
                _libertyBTreePoolMap[graph.resPath] = bTreePool;
                bTreePool.PreInit();
            }
            
            foreach (var graph in graphs)
            {
                id2GraphPathMap[graph.graphId] = graph.resPath;
            }

            LibertyManager.GetInstance("LibertyManager").AIManager = this;
            this.transform.parent = LibertyManager.GetInstance("LibertyManager").transform;
            if (LibertyAIUtils.PlayerController && LibertyAIUtils.PlayerController.playerEntity)
            {
                AddAIEntity(LibertyAIUtils.PlayerController.playerEntity.AIEntity);
            }
        }


        public string GetGraphResPath(int graphId)
        {
            string s = "";
            id2GraphPathMap.TryGetValue(graphId, out s);
            return s;
        }
        
        
        public bool AddNpc(AIBirthData birthData)
        {
            GameObject graph = null;
            LibertyBTreePool bTreePool = null;
            if (!string.IsNullOrEmpty(birthData.graphResPath))
            {
                if (_libertyBTreePoolMap.TryGetValue(birthData.graphResPath,out bTreePool))
                {
                    _uniqueId2GraphResPathMap[birthData.uniqueId] = birthData.graphResPath;
                    graph = bTreePool.GetItem();
                    
                    Debug.Log(LogModule.LibertyScene,"获得行为树：" + birthData.uniqueId);
                }
            }

            if (graph == null)
            {
                return false;
            }
            
            bool success = _npcBirthManager.AddNpc(birthData,graph);
            if (!success && bTreePool != null)
            {
                bTreePool.RecoverItem(graph);  // 不成功行为树回池
                Debug.Log(LogModule.LibertyScene,"回收行为树：" + birthData.uniqueId);
            }
            return success;
        }

        public bool AddNpc(AIBirthData birthData, int graphId)
        {
            id2GraphPathMap.TryGetValue(graphId, out string graphResPath);
            if (graphResPath!=null)
            {
                birthData.graphResPath = graphResPath;
                return AddNpc(birthData);
            }
            return false;
        }
        
        public bool AddAIEntity(AIEntity aiEntity)
        {
            return _npcBirthManager.AddAIEntity(aiEntity);
        }
        
        public bool RemoveNpc(int uniqueId)
        {
            return _npcBirthManager.RemoveNpc(uniqueId);
        }

        public void ReverseGraph(int uniqueId)
        {
            var npc = _npcBirthManager.GetNpc(uniqueId);
            if (_uniqueId2GraphResPathMap.TryGetValue(uniqueId,out var resPath))
            {
                if (_libertyBTreePoolMap.TryGetValue(resPath, out var bTreePool))
                {
                    if (npc.graph && npc.graph.graph)
                    {
                        npc.graph.graph.Stop();
                        bTreePool.RecoverItem(npc.graph.gameObject);
                        Debug.Log(LogModule.LibertyScene, "回收行为树：" + uniqueId);
                    }
                }
                _uniqueId2GraphResPathMap.Remove(uniqueId);
            }
        }
        
        //弃用
        // 销毁所有Npc和车辆
        public void Clear()
        {
            _dynamicNpcManager.Dispose();
            _carBirthManager.Clear();
            _npcBirthManager.Clear();

            foreach (var libertyBTreePool in _libertyBTreePoolMap)
            {
                libertyBTreePool.Value.Destroy();
            }
            _libertyBTreePoolMap.Clear();
            _uniqueId2GraphResPathMap.Clear();
        }

        // 销毁当前所有Npc和车辆，准备重新生成
        public void ClearCurrentAI()
        {
            _carBirthManager.Clear();
            _npcBirthManager.Clear();
        }

        private void OnDestroy()
        {
            foreach (var libertyBTreePool in _libertyBTreePoolMap)
            {
                libertyBTreePool.Value.Destroy();
            }
            _libertyBTreePoolMap.Clear();
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            if (graphs!=null)
            {
                foreach (var pathHolder in graphs)
                {
                    if (pathHolder.graph!=null)
                    {
                        pathHolder.resPath = AssetDatabase.GetAssetPath(pathHolder.graph.gameObject);
                    }
                    else
                    {
                        pathHolder.resPath = "";
                    }
                }
            }
            
        }
#endif
    
    }
}
